/*
 * Copyright 2010-2025 JetBrains s.r.o. and Kotlin Programming Language contributors.
 * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
 */

package org.jetbrains.kotlin.generators.tests

import org.jetbrains.kotlin.generators.util.TestGeneratorUtil
import java.io.File

fun main() {
    generateKt62920StressTest()
}

private fun generateKt62920StressTest() {
    val rootDir = File("native/native.tests/stress/testData")
    rootDir.resolve("kt62920.kt").writeText(buildString {
        val maxStage = 1000
        val threadsCount = 10
        // workaround hack: please keep the string below indented, otherwise the `testCompareAll()` incorrectly handles the "// FILE:" directive
        appendLine(
            """
            // This file is generated by ${TestGeneratorUtil.getMainClassName()}. DO NOT MODIFY MANUALLY
            // KIND: STANDALONE_NO_TR
            // MODULE: cinterop
            // FILE: objclib.def
            language = Objective-C
            ---
            #include <objc/NSObject.h>

            void useObject(id) {}

            // MODULE: main(cinterop)
            // FILE: main.kt
            @file:OptIn(kotlin.ExperimentalStdlibApi::class, kotlinx.cinterop.ExperimentalForeignApi::class)

            import objclib.*

            import kotlin.concurrent.AtomicInt
            import kotlin.concurrent.AtomicIntArray
            import kotlin.native.concurrent.*
            """.trimIndent()
        )

        // Define all the classes
        (1..maxStage).forEach {
            appendLine("class C$it")
        }

        // Actual test procedure
        appendLine(
            """
            const val MAX_STAGE = $maxStage

            val canRunStage = AtomicInt(0)
            val hasRunStage = AtomicIntArray(MAX_STAGE + 1)

            fun test() {
                hasRunStage.getAndIncrement(0)
            """.trimIndent()
        )

        // Define all test cases
        (1..maxStage).forEach {
            appendLine(
                """

                while (canRunStage.value != $it) {}
                useObject(C$it())
                hasRunStage.getAndIncrement($it)
                """.replaceIndent("    ")
            )
        }

        // Close the test procedure. And define test entry point.
        appendLine(
            """
            }

            fun main() {
                val workers = Array($threadsCount) { Worker.start() }

                workers.forEach { it.executeAfter(0, ::test) }

                while (hasRunStage[0] != workers.size) {}
                (1..MAX_STAGE).forEach { stage ->
                    canRunStage.value = stage
                    while (hasRunStage[stage] != workers.size) {}
                }

                workers.forEach { it.requestTermination().result }
            }
            """.trimIndent()
        )
    })
}